import * as $util from '../lib/hc-util.js'

const hc$groovy$editor = {
    template: `
            <div class='hc-groovy'>
                <div v-if='panel' class='hc-groovy-panel'>
                    <span></span>
                    <el-collapse value="vari">
                        <el-collapse-item v-if="panel.vari" name='vari' style='padding-bottom: 0px;'>
                            <template slot="title">
                                <span class='hc-groovy-panel-title'>特征变量</span>
                            </template>
                            <el-tree :indent='4' style="background-color: inherit;" :data="variables" node-key="id" :props="{children:'list',label:'label'}" empty-text="暂无特征变量">
                                <span style='position: relative;' slot-scope="{node, data}">
                                    <span :tooltip='data.label' draggable='true' @dragstart='handleDragStart($event,data)'>
                                        {{ data.label }}</span>
    
                                </span>
                            </el-tree>
                        </el-collapse-item>
                        <el-collapse-item v-if="panel.data" name='data'>
                            <template slot="title">
                                <span class='hc-groovy-panel-title'>用户数据</span>
                            </template>
                            <el-tree style="background-color: inherit;" :data="userdatas" node-key="uid" :props="{children:'list',label:'label'}" empty-text="暂无用户数据">
                                <span slot-scope="{node, data}" :placeholder="data.label">
                                    <span v-if="data.nodetype == 'category'" class='hc-groovy-item' :nodetype='data.nodetype'>
                                        {{ data.label }}</span>
                                    
                                    <span v-else draggable='true' @dragstart='handleDragStart($event,data)' class='hc-groovy-item'>
                                        {{ data.label }}</span>
                                </span>
                            </el-tree>
                        </el-collapse-item>
                        <el-collapse-item v-if="panel.func" name='func'>
                            <template slot="title">
                                <span class='hc-groovy-panel-title'>用户函数</span>
                            </template>
                            <el-tree style="background-color: inherit;" :data="functions" node-key="id" empty-text="暂无用户函数">
                                <span slot-scope="{node, data}" :placeholder="data.label">
                                    <span draggable='true' @dragstart='handleDragStart($event,data)'>
                                        {{ data.label }}</span>
                                </span>
                            </el-tree>
                        </el-collapse-item>
                        <el-collapse-item v-if="panel.snip" name='snip'>
                            <template slot="title">
                                <span class='hc-groovy-panel-title'>代码片段</span>
                            </template>
                            <el-tree style="background-color: inherit;" :data="snipcodes" node-key="uid"  empty-text="暂无代码片段">
                                <span slot-scope="{node, data}">
                                    <span draggable='true' @dragstart='handleDragStart($event,data)'>
                                        {{ data.label }}</span>
                                </span>
                            </el-tree>
                        </el-collapse-item>
                        <el-collapse-item v-if="panel.rule" name='rule'>
                            <template slot="title">
                                <span class='hc-groovy-panel-title'>决策组件</span>
                            </template>
                            <el-tree :indent='4' style="background-color: inherit;" :data="ruleComponents" node-key="rrid" :props="{children:'list',label:'rname'}" empty-text="暂无规则组件">
                                <span slot-scope="{node, data}">
                                    <span v-if="data.nodetype == 'category'" class='hc-groovy-item' :nodetype='data.nodetype'>
                                        {{ data.rname }}</span>
    
                                    <span v-else draggable='true' @dragstart='handleDragStart($event,data)' class='hc-groovy-item'>
                                        {{ data.rname }}</span>
                                </span>
                            </el-tree>
                        </el-collapse-item>
                    </el-collapse>
                </div>
                <pre class='hc-groovy-editor' :readonly='readonly' ref='editor'></pre>
            </div>
                `,
    data: function() {
        return {
            valueInEditor: '',
            editor: null,

            variables: [],
            userdatas: [],
            functions: [],
            snipcodes: [],
            ruleComponents: [],

            langTools: null,
        }
    },
    created: function() {
        this.langTools = ace.require("ace/ext/language_tools");

        this.valueInEditor = this.value;

        this.loadVariOnPanel();
        this.loadDataOnPanel();
        this.loadSnipOnPanel();
        this.loadFuncOnPanel();
        this.loadRuleOnPanel();
    },
    props: {
        value: {
            type: [String, Object],
            required: true
        },
        readonly: {
            type: Boolean,
            default: false,
        },
        maxlines: {
            type: Number,
            default: 2000
        },
        minlines: {
            type: Number,
            default: 24,
        },
        panel: {
            default () {
                return {
                    vari: true,
                    data: true,
                    func: true,
                    snip: true,
                    rule: true
                }
            },
        }
    },
    mounted: function() {
        if (typeof(ace) == 'undefined') {
            console.error('hc-groovy-editor component must refer to ace.js');
            return;
        }

        let dom = this.$refs['editor'];

        this.editor = ace.edit(dom, {
            mode: "ace/mode/groovy",
            theme: 'ace/theme/chrome',
            maxLines: this.maxlines,
            minLines: this.minlines,
            readOnly: this.readonly,
            highlightActiveLine: false,
            highlightSelectedWord: true,
            fontSize: 14,
            wrap: true,
            tabSize: 4,
            showLineNumbers: true,
            showGutter: true,
            showPrintMargin: false,
            displayIndentGuides: false,
            fixedWidthGutter: true,
            value: this.value,
        });

        // enable autocompletion and snippets
        this.editor.setOptions({
            enableBasicAutocompletion: true,
            enableSnippets: true,
            enableLiveAutocompletion: true
        });

        this.editor.getSession().on('change', this.handleChange)
    },
    watch: {
        value: function(newVal, oldVal) {
            //block update editor duplicatedly, otherwise cause the wrong cursor location
            if (this.valueInEditor != newVal) {
                this.editor.setValue(newVal);
                this.editor.clearSelection()
            }
        },
        readonly: function(newVal, oldVal) {
            if (newVal != oldVal)
                this.editor.setReadOnly(newVal);
        }
    },
    methods: {
        addCompleter(wordsList) {
            this.langTools.addCompleter({
                getCompletions: function(editor, session, pos, prefix, callback) {
                    if (prefix.length === 0) {
                        callback(null, []);
                        return
                    }
                    callback(null, wordsList);
                }
            });
        },
        handleChange() {
            this.valueInEditor = this.editor.getSession().getValue();
            this.$emit('input', this.valueInEditor)
        },

        handleDragStart(event, data) {
            event.dataTransfer.effectAllowed = 'copy'
            event.dataTransfer.setData('text/plain', data.snipCode);
        },

        loadVariOnPanel() {
            let variRuleDef = $pinfo.ruleList.find(it => it.rtype == 'variable');
            if(!variRuleDef)
            {
                console.warn('no variable definition in $pinfo');
                return;
            };
            
            this.variables = variRuleDef.list;
            let variableCompletionList = [];
            $util.$tree.traverseRoute(this.variables, function(it, route) {
                it.label = it.name ? it.code + ":" + it.name : it.code;
                it.snipCode = route.map(it => it.code).join('.');
                variableCompletionList.push({
                    caption: it.snipCode,
                    value: it.snipCode,
                    score: 1000,
                    meta: '特征变量',
                });
            });
            this.addCompleter(variableCompletionList);
        },
        
        loadDataOnPanel() {
            let dataList = $pinfo.ruleList.filter(it => it.rtype.startsWith('data:'));
            dataList = dataList.map(it => {
                let classPrefix = it.rpath;
                classPrefix = classPrefix.substr(classPrefix.indexOf('/') + 1);
                classPrefix = classPrefix.split('/').join('.')
                return {
                    nodetype: 'category',
                    rtyp: it.rtype, //dressup the tree according to rtype further in future
                    code: classPrefix,
                    name: it.rname,
                    label: it.rname,
                    list: $util.$tree.clone(it.list),
                };
            });
            let codeCompletionList = [];
            $util.$tree.traverseRoute(dataList, function(it, route) {
                it.label = it.nodetype === 'category' ? it.name : (it.name ? it.code + ":" + it.name : it.code);
                it.snipCode = route.map(it => it.code).join('.');
                it.uid = it.snapCode;
                codeCompletionList.push({
                    caption: it.snipCode,
                    value: it.snipCode,
                    score: 1000,
                    meta: '用户数据',
                });
            });
            this.addCompleter(codeCompletionList);
            this.userdatas = dataList;
        },
        
        loadFuncOnPanel() {
            let funcRuleDef = $pinfo.ruleList.find(it => it.rtype == 'function');
            if(!funcRuleDef)
            {
                console.warn('no function definition in $pinfo');
                return;
            };
            // let classPrefix = funcRuleDef.rpath;
            // classPrefix = classPrefix.substr(classPrefix.indexOf('/') + 1);
            // classPrefix = classPrefix.split('/').join('.')
            let classPrefix = $util.rpath(funcRuleDef).raccesscode();

            this.functions = funcRuleDef ? funcRuleDef.list : [];
            this.functions.forEach(it => {
                it.label = it.code + (it.name ? ('(' + it.name +
                    ')') : '');
                let args = it.args.sort(function(a, b) {
                    return a.id - b.id
                });
                it.snipCode = classPrefix + '.' + it.code + '(' + args.map(it => it.code).join(',') + ')';
            });
            this.addCompleter(this.functions.map(
                it => {
                    return {
                        caption: it.label,
                        value: it.snipCode,
                        score: 1000,
                        meta: '自定义函数'
                    }
                }));
        },

        loadSnipOnPanel() {
            // {
            //     label: 'if-elseif',
            //     snipCode: 'if(condition1){//code here\n}else if(condition2){//code here\n}else{//code here\n};'
            // },
            // {
            //     label: '...',
            //     snipCode: '建设中'
            // },
        },

        loadRuleOnPanel() {
            let ruleCompletionList = [];
            let ruleList = $pinfo.ruleList.filter(it => it.rtype.startsWith('rule:'));

            let ruleTypes = {};
            ruleList.forEach(it => {
                //trim the project code
                let rpath = it.rpath;
                rpath = rpath.substr(rpath.indexOf('/') + 1);
                // it.snipCode = `apply(${rpath.split('/').join('.')}.rule)`;
                let snipCode = `apply(${rpath.split('/').join('.')}.rule)`;
                
                ruleCompletionList.push({
                    caption: it.rname,
                    value: it.snipCode,
                    score: 1000,
                    meta: '规则组件'
                });

                if (!ruleTypes[it.rtype]) ruleTypes[it.rtype] = [];

                // ruleTypes[it.rtype].push(it);
                ruleTypes[it.rtype].push({rpath:it.rpath,rtype:it.rtype,rname:it.rname,snipCode:snipCode});

            });
            this.addCompleter(ruleCompletionList);

            let ruleTree = [];
            $config.componentList.forEach(it => {
                if (!ruleTypes[it.rtype]) return;
                ruleTree.push({
                    // rid: it.rtype,
                    nodetype: 'category',
                    rtype: it.rtype,
                    rname: it.rname,
                    list: ruleTypes[it.rtype],
                });

            });
            
            $util.$tree.createId(ruleTree,'rrid')
            
            this.ruleComponents = ruleTree;
        },

    },
    destroyed: function() {
        this.editor.destroy();
        this.editor.container.remove();
    },

};

Vue.component('hc-groovy-editor', hc$groovy$editor);
